Passed
Pull Request — master (#182)
by
unknown
01:48
created

DateUtilsAdapter.getAllWorkingDayOfYearByMonth   A

Complexity

Conditions 2

Size

Total Lines 25
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 23
dl 0
loc 25
rs 9.328
c 0
b 0
f 0
1
import { Injectable } from '@nestjs/common';
2
import {
3
  format as fnsFormat,
4
  isWeekend as fnsIsWeekend,
5
  getDaysInMonth as fnsGetDaysInMonth,
6
  eachDayOfInterval,
7
  addDays,
8
  getYear
9
} from 'date-fns';
10
import { IDateUtils } from 'src/Application/IDateUtils';
11
import { WorkingDayOfYearByMonth } from 'src/Domain/HumanResource/MealTicket/Strategy/WorkingDayOfYearByMonth';
12
13
@Injectable()
14
export class DateUtilsAdapter implements IDateUtils {
15
  public format(date: Date, format: string): string {
16
    return fnsFormat(date, format);
17
  }
18
19
  public getDaysInMonth(date: Date): number {
20
    return fnsGetDaysInMonth(date);
21
  }
22
23
  public isWeekend(date: Date): boolean {
24
    return fnsIsWeekend(date);
25
  }
26
27
  public getCurrentDate(): Date {
28
    return new Date();
29
  }
30
31
  public getYear(date: Date): number {
32
    return getYear(date);
33
  }
34
35
  public getLastDayOfYear(date: Date): Date {
36
    return new Date(`${getYear(date)}/12/31`);
37
  }
38
39
  public getFirstDayOfYear(date: Date): Date {
40
    return new Date(`${getYear(date)}/01/01`);
41
  }
42
43
  public getCurrentDateToISOString(): string {
44
    return this.getCurrentDate().toISOString();
45
  }
46
47
  public addDaysToDate(date: Date, days: number): Date {
48
    return addDays(date, days);
49
  }
50
51
  public getWorkedDaysDuringAPeriod(start: Date, end: Date): Date[] {
52
    const dates: Date[] = [];
53
    const workedFreeDays: Date[] = [];
54
55
    for (let year = start.getFullYear(); year <= end.getFullYear(); year++) {
56
      workedFreeDays.push(...this.getWorkedFreeDays(year));
57
    }
58
59
    for (const day of eachDayOfInterval({ start, end })) {
60
      if (
61
        this.isWeekend(day) ||
62
        workedFreeDays.filter(d => d.toISOString() === day.toISOString())
63
          .length > 0
64
      ) {
65
        continue;
66
      }
67
68
      dates.push(day);
69
    }
70
71
    return dates;
72
  }
73
74
  public getAllWorkingDayOfYearByMonth(date: Date): WorkingDayOfYearByMonth[] {
75
    const lastDayOfYear = this.getLastDayOfYear(date);
76
    const firstDayOfYear = this.getFirstDayOfYear(date);
77
78
    const workedDaysOfYear = this.getWorkedDaysDuringAPeriod(
79
      firstDayOfYear,
80
      lastDayOfYear
81
    );
82
83
    const defaultValues: WorkingDayOfYearByMonth[] = [];
84
85
    return workedDaysOfYear.reduce((prev, next) => {
86
      const currentMonth = next.getMonth() + 1;
87
      const itemWithMonth = prev.find(item => item.month === currentMonth);
88
89
      if (itemWithMonth) {
90
        itemWithMonth.addOneWorkingDay();
91
        return prev;
92
      }
93
      const working = new WorkingDayOfYearByMonth(currentMonth);
94
      working.addOneWorkingDay();
95
96
      return [...prev, working];
97
    }, defaultValues);
98
  }
99
100
  public getWorkedFreeDays(year: number): Date[] {
101
    const fixedDays: Date[] = [
102
      new Date(`${year}-01-01`), // New Year's Day
103
      new Date(`${year}-05-01`), // Labour Day
104
      new Date(`${year}-05-08`), // Victory in 1945
105
      new Date(`${year}-07-14`), // National Day
106
      new Date(`${year}-08-15`), // Assumption
107
      new Date(`${year}-11-01`), // All Saints' Day
108
      new Date(`${year}-11-11`), // The Armistice
109
      new Date(`${year}-12-25`) // Christmas
110
    ];
111
112
    const easterDate = this.getEasterDate(year);
113
    const easterDays: Date[] = [
114
      addDays(easterDate, 1), // Easter Monday
115
      addDays(easterDate, 39) // Ascension
116
    ];
117
118
    return [...fixedDays, ...easterDays];
119
  }
120
121
  public getEasterDate(year: number): Date {
122
    const a = year % 19;
123
    const b = Math.floor(year / 100);
124
    const c = year % 100;
125
    const d = Math.floor(b / 4);
126
    const e = b % 4;
127
    const f = Math.floor((b + 8) / 25);
128
    const g = Math.floor((b - f + 1) / 3);
129
    const h = (19 * a + b - d - g + 15) % 30;
130
    const i = Math.floor(c / 4);
131
    const k = c % 4;
132
    const l = (32 + 2 * e + 2 * i - h - k) % 7;
133
    const m = Math.floor((a + 11 * h + 22 * l) / 451);
134
    const n0 = h + l + 7 * m + 114;
135
    const n = Math.floor(n0 / 31) - 1;
136
    const p = (n0 % 31) + 1;
137
138
    return new Date(year, n, p);
139
  }
140
141
  public getLeaveDuration(
142
    startDate: string,
143
    isStartsAllDay: boolean,
144
    endDate: string,
145
    isEndsAllDay: boolean
146
  ): number {
147
    let duration = this.getWorkedDaysDuringAPeriod(
148
      new Date(startDate),
149
      new Date(endDate)
150
    ).length;
151
152
    if (false === isStartsAllDay) {
153
      duration -= 0.5;
154
    }
155
156
    if (false === isEndsAllDay && duration > 0.5) {
157
      duration -= 0.5;
158
    }
159
160
    return duration;
161
  }
162
}
163